import Vue from 'vue';
import axios from 'axios';

class TKmsBridgeClient {
    constructor() {
        this.config = {
            clientId: ['c', (new Date()).getTime(), parseInt(100 * Math.random())].join(''),
            apiUrl: "https://localhost:31021",
            //apiUrl: "https://dq.hhdata.cn:31022",
            dbKey: "cock"
        };
        this.kmsConfig = null;
        /*
            {
                kmsUrl: me.config.clientKmsUrl,
                version: me.config.version,
                peerOptions: me.config.peerOptions,
                svrTime: (new Date()).getTime()
            }
        */
        this.kmsClient = null;
        this.cameras = [];
    };
    callApi(apiPath, ps, method) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var url = [me.config.apiUrl, apiPath].join('/');

                var data = (ps && ps != null) ? ps : {};
                if (method == "GET") {
                    axios.get(url, data).then(res => {
                        success(res);
                    })
                } else {
                    axios.post(url, data).then(res => {
                        success(res);
                    })
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    query(key, ps) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var apiPath = "common/mysqldb/query";
                var postPs = {
                    appId: me.config.dbKey,
                    key: key,
                    psJson: JSON.stringify(ps)
                }
                me.callApi(apiPath, postPs, "POST").then(res => {
                    var result = res && res.data ? res.data.result : null;
                    success(result);
                })
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    getSvrTime() {
        var me = this;
        var res = {
            requestTm: 0,
            responseTm: 0,
            svrTm: 0,
        };
        return new Promise((success, faild) => {
            try {
                res.requestTm = (new Date()).getTime();
                me.callApi("kms/bridge/getSvrTime", {}).then(resObj => {
                    res.requestTm = (new Date()).getTime();
                    res.svrTm = resObj.data.data;
                    success(res);
                });
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    getKmsConfig() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.kmsConfig && me.kmsConfig != null) {
                    success(me.kmsConfig);
                } else {
                    me.callApi("kms/bridge/getConfig", {}).then(_config => {
                        me.kmsConfig = _config.data.data;
                        success(me.kmsConfig);
                    });
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    clearObjs() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                me.callApi("kms/bridge/clearObjs", {}).then(_ => {
                    success();
                });
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    getKmsClient() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.kmsClient && me.kmsClient != null) {
                    success(me.kmsClient);
                } else {
                    me.getKmsConfig().then(_ => {
                        kurentoClient(me.kmsConfig.kmsUrl, function(error, _client) {
                            me.kmsClient = _client;
                            if (error) {
                                console.log(error);
                                success(null)
                            } else {
                                _client.on('disconnect', function() {
                                    delete me['kmsClient'];
                                })
                                _client.getServerManager().then(_svr => {
                                    me.kmsSvr = _svr;
                                    return me.getDevices();
                                }).then(_devs => {
                                    me.cameras = _devs.videoinput;
                                    return me.getKmsConfig();
                                }).then(_config => {
                                    success(_client);
                                })

                            }
                        });
                    })
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    getDevices() {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(_ => {
                    return navigator.mediaDevices.enumerateDevices();
                }).then(function(devs) {
                    try {
                        for (var i = 0; i < devs.length; i++) {
                            var item = devs[i];
                            if (!res[item.kind]) {
                                res[item.kind] = []
                            }
                            res[item.kind].push(item);
                        }
                    } catch (er) {
                        console.log(er);
                    }
                    success(res);
                }).catch(function() {
                    success(res);
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    getChannel(channelCode) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                me.callApi("kms/bridge/getChannel", { channelCode: channelCode }).then(resObj => {
                    res = resObj && resObj.data && resObj.data.data ? resObj.data.data : null;
                    success(res);
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    setChannel(channelCode, seatCodes) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                var ps = {
                    channelCode: channelCode,
                    seatCodes: seatCodes
                }
                me.callApi("kms/bridge/setChannel", ps).then(resObj => {
                    res = resObj && resObj.data && resObj.data.data ? resObj.data.data : null;
                    success(res);
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    createEnd(channelKmsId, endCode, channelCode) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                var ps = {
                    channelCode: channelCode,
                    endCode: endCode,
                    channelKmsId: channelKmsId,
                    clientId: me.config.clientId
                }
                me.callApi("kms/bridge/createEnd", ps).then(resObj => {
                    res = resObj && resObj.data && resObj.data.data ? resObj.data.data : null;
                    if (res == null) {
                        success(res);
                    } else {
                        var endKmsId = res.kmsId;
                        me.getKmsClient().then(client => {
                            client.getMediaobjectById(endKmsId).then(end => {
                                end.tag = res;
                                success(end);
                            })
                        })
                    }
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    connectMedia(srcKmsId, targetKmsId, mediaType) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                var ps = {
                    srcId: srcKmsId,
                    tarId: targetKmsId,
                    mediaType: mediaType
                }
                me.callApi("kms/bridge/connectMedia", ps).then(resObj => {
                    res = resObj && resObj.data && resObj.data.data ? resObj.data.data : null;
                    success(res);
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    startRecord(srcKmsId, recFn) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                var ps = {
                    srcId: srcKmsId,
                    recFn: recFn
                }
                me.callApi("kms/bridge/startRecord", ps).then(resObj => {
                    res = resObj && resObj.data && resObj.data.data ? resObj.data.data : null;
                    success(res);
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    stopRecord(recorderKmsId) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                var ps = {
                    recorderId: recorderKmsId
                }
                me.callApi("kms/bridge/stopRecord", ps).then(resObj => {
                    res = resObj && resObj.data && resObj.data.data ? resObj.data.data : null;
                    success(res);
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    createPeer(peerType, video, cameraId) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                me.getKmsClient().then(_ => {
                    return me.getKmsConfig();
                }).then(_ => {
                    var peerFactories = {
                        s: kurentoUtils.WebRtcPeer.WebRtcPeerSendonly,
                        r: kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly,
                        sr: kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv
                    };
                    var createFactory = peerFactories[peerType];
                    var peerOptions = me.kmsConfig.peerOptions;
                    peerOptions.localVideo = peerType == 's' ? video : null;
                    peerOptions.remoteVideo = peerType == 'r' ? video : null;
                    var videoDeviceId = cameraId || "";
                    var cameras = me.cameras.filter(c => {
                        return c.deviceId == videoDeviceId && videoDeviceId != "";
                    });
                    if (cameras.length > 0) {
                        peerOptions.mediaConstraints.video.deviceId = videoDeviceId;
                    }
                    var wrPeer = createFactory(peerOptions, function(erP) {
                        wrPeer.peerOptions = peerOptions;
                        wrPeer.isScreen = false;
                        success(wrPeer);
                    });
                })
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };
    bindPeerEnd(peer, end) {
        var me = this;
        var res = {};
        return new Promise((success, faild) => {
            try {
                end.on('OnIceCandidate', function(event) {
                    var candidate = event.candidate;
                    peer.addIceCandidate(candidate);
                    console.log('candidate w->p', candidate);
                });
                peer.on('icecandidate', function(candidate) {
                    var iceCandidate = kurentoClient.register.complexTypes.IceCandidate(candidate);
                    end.addIceCandidate(iceCandidate);
                    console.log('candidate p->w', iceCandidate);
                });
                peer.generateOffer(function(er0, sdpOffer) {
                    end.processOffer(sdpOffer, function(er1, sdpAnswer) {
                        peer.processAnswer(sdpAnswer, function(er2) {
                            end.gatherCandidates(function(er3) {
                                success();
                            });
                        });
                    });
                });
            } catch (er) {
                console.log(er);
                success(res);
            }
        });
    };



    setCamera(peer, newDeviceId) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var currentDeviceId = peer.localVideo.srcObject.getVideoTracks()[0].getSettings().deviceId;
                if (currentDeviceId != newDeviceId) {
                    var stream = peer.localVideo.srcObject();
                    stream.getTracks().forEach(t => {
                        t.stop();
                    });
                }
                var mediaConstraints = peer.peerOptions.mediaConstraints;
                mediaConstraints.video.deviceId = newDeviceId;
                navigator.mediaDevices.getUserMedia(mediaConstraints).then(function(stream) {
                    try {
                        peer.localVideo.srcObject = stream;
                        var streamTracks = {};
                        stream.getTracks().forEach(st => {
                            try {
                                streamTracks[st.kind] = st;
                            } catch (eer) {
                                console.log(eer);
                            }
                        });
                        peer.peerConnection.getSenders().forEach(_sender => {
                            try {
                                var kind = _sender.track.kind;
                                _sender.track.stop();
                                var stTrack = streamTracks[kind];
                                _sender.replaceTrack(stTrack);
                            } catch (eer) {
                                console.log(eer);
                            }
                        });
                    } catch (eSet) {
                        console.log(eSet);
                    }
                    try {
                        success();
                    } catch (eer) {
                        console.log(eer);
                    }
                }).catch(function(erSet) {
                    console.log(erSet);
                    try {
                        success();
                    } catch (eer) {
                        console.log(eer);
                    }
                });

            } catch (er) {
                console.log(er);
                try {
                    success();
                } catch (eer) {
                    console.log(eer);
                }
            }
        });
    };
    setCameraByIndex(peer, index) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.cameras.length > 0) {
                    var camera = index > me.cameras.length ? me.cameras[0] : me.cameras[index];
                    me.setCamera(peer, camera.deviceId).then(_res => {
                        success(_res);
                    })
                } else {
                    success();
                }
            } catch (er) {
                console.log(er);
                try {
                    success();
                } catch (eer) {
                    console.log(eer);
                }
            }
        });
    };
    shareScreen(peer, width, height) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var wWidth = width && width > 0 ? width : (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth);
                var wHeight = height && height > 0 ? height : (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight);
                var screenConstraints = { video: { width: { max: wWidth }, height: { max: wHeight } }, audio: true };
                var sender = null;
                if (navigator.mediaDevices.getDisplayMedia) {
                    navigator.mediaDevices.getDisplayMedia(screenConstraints).then(
                        function(stream) {
                            let videoTrack = stream.getVideoTracks()[0];
                            peer.localVideo.srcObject = stream;
                            sender = peer.peerConnection.getSenders().find(function(s) {
                                return s.track.kind == videoTrack.kind;
                            });
                            sender.track.stop();
                            sender.replaceTrack(videoTrack);
                            success();
                        }
                    )
                } else {
                    success();
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    setPeerStream(peer, stream) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var oldStream = peer.getLocalStream();
                if (oldStream && oldStream != null) {
                    oldStream.getTracks().forEach(t => {
                        t.stop();
                    });
                }
                try {
                    peer.localVideo.srcObject = stream;
                    var streamTracks = {};
                    stream.getTracks().forEach(st => {
                        try {
                            streamTracks[st.kind] = st;
                        } catch (eer) {
                            console.log(eer);
                        }
                    });
                    peer.peerConnection.getSenders().forEach(_sender => {
                        try {
                            var kind = _sender.track.kind;
                            _sender.track.stop();
                            var stTrack = streamTracks[kind];
                            _sender.replaceTrack(stTrack);
                        } catch (eer) {
                            console.log(eer);
                        }
                    });
                } catch (eSet) {
                    console.log(eSet);
                }
                try {
                    success();
                } catch (eer) {
                    console.log(eer);
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    fullScreen(peer) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                var element = peer.remoteVideo;
                me.fullScreenElement(element).then(_ => {
                    success();
                })
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    fullScreenElement(element) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (element.requestFullscreen) {
                    element.requestFullscreen();
                } else if (element.msRequestFullscreen) {
                    element.msRequestFullscreen();
                } else if (element.mozRequestFullScreen) {
                    element.mozRequestFullScreen();
                } else if (element.webkitRequestFullscreen) {
                    element.webkitRequestFullscreen();
                }
                success();
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };

    /*
        var defaultSettings = {
            channelCode: "ch",
            seatCodes: ['s01', 's02'],
            views: [{
                code: "v01",
                viewType: 's',
                video: null,
                defaultSeatCode: "",
                cameraIndex: 0
            }]
        };
    */
    createChannel(channelSettings) {
        var me = this;
        var ch = new TKmsChannel();
        ch.bridge = me;
        return new Promise((success, faild) => {
            try {
                var seatCodes = (channelSettings.seatCodes || []).join(",");
                me.setChannel(channelSettings.channelCode, seatCodes).then(chInfo => {
                    ch.channelInfo = chInfo;
                    var index = 0;
                    var items = channelSettings.views || [];
                    items.forEach(item => {
                        ch.createView(item.code, item.viewType, item.video, item.cameraIndex, item.defaultSeatCode)
                            //var view = new TKmsView(ch, item.code, item.viewType, item.cameraIndex, item.defaultSeatCode);
                            //ch.views[view.viewCode] = view;
                    });
                    success(ch);
                })
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
};
class TKmsChannel {
    constructor(bridge) {
        this.channelInfo = {};
        this.bridge = bridge;
        this.views = {};
    };
    createView(viewCode, viewType, video, defaultCameraIndex, playSeatCode) {
        var me = this;
        try {
            if (!(me.views[viewCode] && me.views[viewCode] != null)) {
                var view = new TKmsView(me, viewCode, viewType, defaultCameraIndex, playSeatCode);
                view.video = video;
                me.views[view.viewCode] = view;
            }
        } catch (er) {
            console.log(er);
        }
        return me.views[view.viewCode];
    };

};
class TKmsView {
    constructor(channel, viewCode, viewType, defaultCameraIndex, playSeatCode) {
        this.channel = channel;
        this.viewCode = viewCode || "";
        this.viewType = viewType || "s";
        this.peer = null;
        this.video = null;
        this.end = null;
        this.defaultCameraIndex = defaultCameraIndex || 0;
        this.recorderId = "";
        this.playSeatCode = playSeatCode || "";
    };
    close() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.peer && me.peer != null) {
                    me.peer.dispose();
                    me.peer = null;
                }
                var closeRecord = () => {
                    return new Promise((su, fa) => {
                        if (me.recorderId && me.recorderId != null && me.recorderId.length > 0) {
                            me.channel.bridge.stopRecord(me.recorderId).then(_ => {
                                me.recorderId = "";
                                su();
                            });
                        } else {
                            su();
                        }
                    });
                }
                var closeEnd = () => {
                    return new Promise((su, fa) => {
                        if (me.end && me.end != null) {
                            me.end.release().then(_ => {
                                me.end = null;
                                su();
                            })
                        } else {
                            su();
                        }
                    });
                }
                closeRecord().then(_ => {
                    return closeEnd();
                }).then(_ => {
                    success();
                })
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    open() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                me.close().then(_ => {
                    var defaultCameraId = me.channel.bridge.cameras.length > me.defaultCameraIndex ? me.channel.bridge.cameras[me.defaultCameraIndex].deviceId : "";
                    return me.channel.bridge.createPeer(me.viewType, me.video, defaultCameraId);
                }).then(_peer => {
                    me.peer = _peer;
                    var chKmsId = me.channel.channelInfo.channel.kmsId;
                    var chCode = me.channel.channelInfo.channel.channelCode;
                    return me.channel.bridge.createEnd(chKmsId, me.viewCode, chCode);
                }).then(end => {
                    me.end = end;
                    return me.channel.bridge.bindPeerEnd(me.peer, me.end);
                }).then(_ => {
                    success();
                });
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    push(seatCode) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.viewType == 's' && seatCode && seatCode != "" && me.channel.channelInfo.seats[seatCode] && me.channel.channelInfo.seats[seatCode] != null) {
                    var tarId = me.channel.channelInfo.seats[seatCode].kmsId;
                    var srcId = me.end.id;
                    me.channel.bridge.connectMedia(srcId, tarId).then(_ => {
                        success();
                    });
                } else {
                    success();
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    play(seatCode) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.viewType == 'r' && seatCode && seatCode != "" && me.channel.channelInfo.seats[seatCode] && me.channel.channelInfo.seats[seatCode] != null) {
                    var srcId = me.channel.channelInfo.seats[seatCode].kmsId;
                    var tarId = me.end.id;
                    me.channel.bridge.connectMedia(srcId, tarId).then(_ => {
                        success();
                    });
                } else {
                    success();
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    startRecord(recFn) {
        var me = this;
        return new Promise((success, faild) => {
            try {
                me.channel.bridge.startRecord(me.end.id, recFn).then(res => {
                    me.recorderId = res.recorderId;
                    success();
                })
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
    stopRecord() {
        var me = this;
        return new Promise((success, faild) => {
            try {
                if (me.recorderId && me.recorderId != null && me.recorderId.length > 0) {
                    me.channel.bridge.stopRecord(this.recorderId).then(_ => {
                        me.recorderId = "";
                        success();
                    })
                } else {
                    success();
                }
            } catch (er) {
                console.log(er);
                success();
            }
        });
    };
};

var bridge = new TKmsBridgeClient();
Vue.prototype.kmsBridge = bridge;